#include "dealer_handler.h"
#include <QSocketNotifier>
#include <QDebug>
#include <QRandomGenerator>
#include <QThread>
#include <QMessageBox>

DealerHandler *DealerHandler::getInstance()
{
    static QMutex mutex;
    static DealerHandler *instance = nullptr;

    if (instance == nullptr)
    {
        QMutexLocker locker(&mutex);
        if (instance == nullptr)
        {
            instance = new DealerHandler();
        }
    }
    return instance;
}

DealerHandler::DealerHandler(QObject *parent)
    : QObject(parent),
      context_(1),
      notifier_(nullptr),
      running_(false),
      network_thread_(new QThread)
{
    // 将对象移动到网络线程
    this->moveToThread(network_thread_);
    // 连接线程退出信号到清理槽函数
    connect(network_thread_, &QThread::finished, this, &DealerHandler::onThreadFinished);
    network_thread_->start();
}

DealerHandler::~DealerHandler()
{
    stop();
    if (network_thread_)
    {
        delete network_thread_;
    }
}

bool DealerHandler::initialize(const QString &server_address)
{
    // 通过信号槽将初始化请求发送到网络线程
    server_address_ = server_address;
    QMetaObject::invokeMethod(this, "innerInitialize", Qt::QueuedConnection);
    return true;
}

void DealerHandler::sendRequest(const QString &method, const QString &body)
{
    QMetaObject::invokeMethod(this, "innerSend", Qt::QueuedConnection, Q_ARG(QString, method), Q_ARG(QString, body));
}

void DealerHandler::stop()
{
    QMutexLocker locker(&socket_mutex_);
    if (running_)
    {
        running_ = false;
        network_thread_->quit();
        network_thread_->wait();
    }
}

void DealerHandler::innerSend(const QString &method, const QString &body)
{
    zmq::message_t method_msg(method.toUtf8().constData(), method.toUtf8().size());
    zmq::message_t body_msg(body.toUtf8().constData(), body.toUtf8().size());

    auto s1 = dealer_socket_.send(method_msg, zmq::send_flags::sndmore); // 多部分消息
    auto s2 = dealer_socket_.send(body_msg, zmq::send_flags::none);

    if (!s1 || !s2)
    {
        emit errorOccurred("发送消息失败");
    }
}

void DealerHandler::innerRecv()
{
    zmq::message_t method_msg, body_msg;

    zmq::pollitem_t items[] = {{dealer_socket_, 0, ZMQ_POLLIN, 0}};
    while (zmq::poll(items, 1, 0) > 0) {
        if (items[0].revents & ZMQ_POLLIN) {
            if (!dealer_socket_.recv(&method_msg)) {
                qWarning() << "Recv error (method):" << zmq_strerror(zmq_errno());
                emit messageReceived("error", "网络无法连接", true);
                break;
            }

            if (!dealer_socket_.recv(&body_msg)) {
                qWarning() << "Incomplete message: missing body";
                emit messageReceived("error", "网络无法连接", true);
                break;
            }

            // 处理消息
            QString method = QString::fromUtf8(
                static_cast<char*>(method_msg.data()), method_msg.size());
            QString body = QString::fromUtf8(
                static_cast<char*>(body_msg.data()), body_msg.size());
            emit messageReceived(method, body);
        }
    }
}

QString DealerHandler::GenerateRandomString(int length)
{
    const QString characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    QString result;
    result.reserve(length);

    for (int i = 0; i < length; ++i)
    {
        int index = QRandomGenerator::global()->bounded(characters.length());
        result.append(characters.at(index));
    }

    return result;
}

void DealerHandler::innerInitialize()
{
    QMutexLocker locker(&socket_mutex_);
    dealer_socket_ = zmq::socket_t(context_, ZMQ_DEALER);
    QString result = GenerateRandomString(16);
    result = "panel-" + result;
    QByteArray identityBytes = result.toUtf8();
    dealer_socket_.setsockopt(ZMQ_IDENTITY, identityBytes.constData(), identityBytes.size());
    dealer_socket_.connect(server_address_.toStdString());
    setupSocketNotifier();
    running_ = true;
    emit connectionStatusChanged(true);
}

void DealerHandler::setupSocketNotifier()
{
    notifier_ = new QSocketNotifier(dealer_socket_.get(zmq::sockopt::fd), QSocketNotifier::Read, this);
    connect(notifier_, &QSocketNotifier::activated, this, &DealerHandler::innerRecv);
}

void DealerHandler::onThreadFinished()
{
    if (notifier_)
    {
        delete notifier_;
        notifier_ = nullptr;
    }
    dealer_socket_.close();
    context_.close();
    emit connectionStatusChanged(false);
}